/*
 * This file is part of b.AMP.
 *
 * b.AMP is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * b.AMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with b.AMP.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __BAMP_PROCESS_HPP__
#define __BAMP_PROCESS_HPP__

#include "async_loop.hpp"
#include "message_ack.hpp"
#include "message_source.hpp"
#include "message_target.hpp"

#include <bamp/message_ptr.hpp>

#include <boost/filesystem.hpp>
#include <boost/functional.hpp>

#include <iostream>
#include <memory>
#include <vector>


namespace bamp
{

    /**
     * A process object runs a program in a separate process. It
     * exchanges serialized messages with the child process through
     * its standard input and output. Serialization/deserialization is
     * performed by the functions supplied in the constructor.
     */
    class Process : public AsyncLoop,
                    public MessageSource,
                    public MessageTarget
    {
    public:

        /**
         * Process descriptor. This structure contains the path to the
         * process' executable file and the list of all its
         * command-line arguments.
         */
        struct Descriptor
        {
            boost::filesystem::path exec;    /// Path to the executable
            std::vector<std::string> args;   /// Command-line arguments
        };

        /**
         * Serializer function type that takes the contents of a
         * message and outputs it in a format supported by the program
         * running in the process.
         */
        typedef boost::function<void(std::ostream&, const Message&)>
        Serializer;
        
        /**
         * Deserializer function type that takes the output of the
         * process and forwards the messages to a target.
         */
        typedef boost::function<void(std::istream&, MessageTarget&)>
        Deserializer;

        /**
         * Initialize an process with a descriptor but do not run it
         * yet. Execution can be controlled using run() and stop().
         */
        Process(const Descriptor desc, Serializer ser, Deserializer des);

        /**
         * Stop the process if it is started and release any resource
         * held.
         */
        virtual ~Process();

        // MessageSource interface
        virtual void setTarget(MessageTarget& target);
        virtual void clearTarget();

        // MessageTarget interface
        virtual void send(const Message& message, MessageAck ack);
        virtual MessageAck send(const Message& message);


    private:

        // AsyncLoop interface
        virtual bool preRun();
        virtual bool postRun();
        virtual bool iteration();
        virtual bool preStop();
        virtual void postStop();

        // Hidden implementation
        struct Implementation;
        std::auto_ptr<Implementation> pimpl;
    };

} // namespace bamp

#endif // __BAMP_PROCESS_HPP__
